import fs from 'fs-extra';
import path from 'path';
import * as vueTemplateCompiler from 'vue-template-compiler';
import { BaseComponentParser } from '../core/BaseComponentParser';
import { VueComponent, ComponentProp, ComponentEvent, ComponentSlot, ComponentMethod, ComponentEventArgument, ComponentMethodParam, ComponentSlotBinding, ComponentMethodReturn } from '../../core/types';
import { FileUtils } from '../utils/FileUtils';
import { CommentUtils } from '../utils/CommentUtils';
import { TypeUtils } from '../utils/TypeUtils';

/**
 * Vue2组件解析器
 */
export class Vue2ComponentParser extends BaseComponentParser {
  /**
   * 构造函数
   * @param scanPaths 要扫描的组件路径
   */
  constructor(scanPaths: string[]) {
    super(scanPaths);
    console.log('初始化Vue2组件解析器');
  }

  /**
   * 解析Vue2组件
   * @param filePath 组件文件路径
   * @returns 组件信息对象
   */
  protected async parseComponent(filePath: string): Promise<VueComponent | null> {
    try {
      // 读取文件内容
      const content = await FileUtils.readFile(filePath);
      if (!content) {
        console.error(`无法读取文件: ${filePath}`);
        return null;
      }

      // 使用Vue编译器解析SFC
      const parsedComponent = vueTemplateCompiler.parseComponent(content);
      
      if (!parsedComponent) {
        console.error(`解析Vue组件 ${filePath} 失败`);
        return null;
      }
      
      // 获取文件状态以获取修改时间
      const stats = await FileUtils.getFileStats(filePath);
      if (!stats) {
        console.error(`无法获取文件状态: ${filePath}`);
        return null;
      }
      
      // 获取相对路径
      const relativeFilePath = FileUtils.getRelativePath(filePath);
      
      // 提取组件信息
      const scriptContent = parsedComponent.script?.content || '';
      const templateContent = parsedComponent.template?.content || '';
      
      // 解析组件名称和描述
      const componentName = await this.extractComponentName(parsedComponent, filePath);
      const description = this.extractComponentDescription(parsedComponent);
      
      // 构建组件对象
      const component: VueComponent = {
        id: this.generateComponentId(relativeFilePath),
        name: componentName,
        description: description,
        filePath: relativeFilePath,
        props: await this.extractProps(parsedComponent, filePath),
        events: await this.extractEvents(parsedComponent, filePath),
        slots: await this.extractSlots(parsedComponent, filePath),
        methods: await this.extractMethods(parsedComponent, filePath),
        createdAt: stats.birthtime.toISOString(),
        updatedAt: stats.mtime.toISOString(),
        vueVersion: '2',
      };
      
      return component;
    } catch (error) {
      console.error(`解析组件 ${filePath} 失败:`, error);
      return null;
    }
  }
  
  /**
   * 提取组件名称
   * @param parsedComponent 解析后的组件对象
   * @param filePath 文件路径
   * @returns 组件名称
   */
  private async extractComponentName(parsedComponent: any, filePath: string): Promise<string> {
    // 默认使用文件名作为组件名
    let componentName = path.basename(filePath, '.vue');
    
    if (!parsedComponent.script) {
      return componentName;
    }
    
    const scriptContent = parsedComponent.script.content;
    
    // 查找导出的name属性
    const nameExportMatch = scriptContent.match(/name\s*:\s*['"]([^'"]+)['"]/);
    if (nameExportMatch && nameExportMatch[1]) {
      return nameExportMatch[1];
    }
    
    // 从脚本注释中查找组件名
    const scriptComments = this.extractComments(scriptContent);
    for (const comment of scriptComments) {
      const nameFromComment = CommentUtils.extractComponentName(comment);
      if (nameFromComment) {
        return nameFromComment;
      }
    }
    
    // 查找template中的顶级注释
    if (parsedComponent.template?.content) {
      const templateComments = this.extractComments(parsedComponent.template.content);
      for (const comment of templateComments) {
        const nameFromComment = CommentUtils.extractComponentName(comment);
        if (nameFromComment) {
          return nameFromComment;
        }
      }
    }
    
    return componentName;
  }
  
  /**
   * 提取组件描述
   * @param parsedComponent 解析后的组件对象
   * @returns 组件描述
   */
  private extractComponentDescription(parsedComponent: any): string {
    // 从脚本注释中查找组件描述
    if (parsedComponent.script?.content) {
      const scriptComments = this.extractComments(parsedComponent.script.content);
      if (scriptComments.length > 0) {
        // 使用第一个块注释作为组件描述
        return CommentUtils.extractDescription(scriptComments[0]);
      }
    }
    
    // 查找template中的顶级注释
    if (parsedComponent.template?.content) {
      const templateComments = this.extractComments(parsedComponent.template.content);
      if (templateComments.length > 0) {
        return CommentUtils.extractDescription(templateComments[0]);
      }
    }
    
    return '';
  }
  
  /**
   * 提取组件属性
   * @param parsedComponent 解析后的组件对象
   * @param filePath 文件路径
   * @returns 组件属性数组
   */
  private async extractProps(parsedComponent: any, filePath: string): Promise<ComponentProp[]> {
    const props: ComponentProp[] = [];
    
    if (!parsedComponent.script?.content) {
      return props;
    }
    
    const scriptContent = parsedComponent.script.content;
    
    // 查找props定义
    // 方式1: props: ['propName', 'propName2']
    const propsArrayMatch = scriptContent.match(/props\s*:\s*\[([\s\S]*?)\]/);
    if (propsArrayMatch) {
      const propsArray = propsArrayMatch[1];
      // 提取所有引号中的属性名
      const propMatches = [...propsArray.matchAll(/['"]([^'"]+)['"]/g)];
      
      for (const match of propMatches) {
        const propName = match[1];
        
        props.push({
          name: propName,
          type: 'any', // 数组形式不提供类型信息
          description: this.findPropDescription(propName, scriptContent),
          required: false,
          values: [],
        });
      }
      
      return props;
    }
    
    // 方式2: props: { propName: Type, propName2: { type: Type, required: true, default: value } }
    const propsObjectMatch = scriptContent.match(/props\s*:\s*\{([\s\S]*?)\}/);
    if (propsObjectMatch) {
      const propsObject = propsObjectMatch[1];
      
      // 提取属性定义
      const propDefinitions = [...propsObject.matchAll(/(\w+)\s*:\s*(?:(\w+)|(\{[\s\S]*?\}))/g)];
      
      for (const definition of propDefinitions) {
        const propName = definition[1];
        const simpleType = definition[2]; // 如果是简单类型，例如 propName: String
        const complexType = definition[3]; // 如果是对象配置，例如 propName: { type: String, required: true }
        
        let type = 'any';
        let required = false;
        let defaultValue: string | undefined;
        let values: string[] = [];
        
        if (simpleType) {
          // 处理简单类型
          type = this.mapVueTypeToString(simpleType);
        } else if (complexType) {
          // 处理对象配置
          // 提取类型
          const typeMatch = complexType.match(/type\s*:\s*(\w+)/);
          if (typeMatch) {
            type = this.mapVueTypeToString(typeMatch[1]);
          }
          
          // 提取是否必填
          const requiredMatch = complexType.match(/required\s*:\s*(true|false)/);
          if (requiredMatch) {
            required = requiredMatch[1] === 'true';
          }
          
          // 提取默认值
          const defaultMatch = complexType.match(/default\s*:\s*(?:function\s*\(\)\s*\{\s*return\s*([^;]+);\s*\}|([^,]+))/);
          if (defaultMatch) {
            defaultValue = (defaultMatch[1] || defaultMatch[2]).trim();
          }
          
          // 提取验证函数中可能的枚举值
          const validatorMatch = complexType.match(/validator\s*:\s*function\s*\([^)]*\)\s*\{[\s\S]*?return\s*\[([^\]]+)\]/);
          if (validatorMatch) {
            const valuesString = validatorMatch[1];
            const valueMatches = [...valuesString.matchAll(/['"]([^'"]+)['"]/g)];
            
            values = valueMatches.map(match => match[1]);
          }
        }
        
        // 从注释中查找类型信息
        const propComment = this.findPropComment(propName, scriptContent);
        const commentType = propComment ? CommentUtils.extractPropType(propComment) : undefined;
        
        // 合并类型信息
        const finalType = TypeUtils.mergeTypes(type, commentType);
        
        // 从注释中查找可能的枚举值
        const commentValues = propComment ? CommentUtils.extractEnumValues(propComment) : [];
        
        // 合并枚举值
        if (commentValues.length > 0) {
          values = [...new Set([...values, ...commentValues])];
        }
        
        props.push({
          name: propName,
          type: finalType,
          description: this.findPropDescription(propName, scriptContent),
          defaultValue: defaultValue,
          required: required,
          values: values,
        });
      }
      
      return props;
    }
    
    return props;
  }
  
  /**
   * 提取组件事件
   * @param parsedComponent 解析后的组件对象
   * @param filePath 文件路径
   * @returns 组件事件数组
   */
  private async extractEvents(parsedComponent: any, filePath: string): Promise<ComponentEvent[]> {
    const events: ComponentEvent[] = [];
    
    if (!parsedComponent.script?.content && !parsedComponent.template?.content) {
      return events;
    }
    
    const scriptContent = parsedComponent.script?.content || '';
    const templateContent = parsedComponent.template?.content || '';
    
    // 从模板中查找$emit调用
    const emitMatches = [...templateContent.matchAll(/\$emit\s*\(\s*['"]([^'"]+)['"]/g)];
    
    for (const match of emitMatches) {
      const eventName = match[1];
      
      // 检查事件是否已存在
      const existingEvent = events.find(e => e.name === eventName);
      if (!existingEvent) {
        // 查找脚本中对该事件的定义，以获取参数信息
        const eventComment = this.findEventComment(eventName, scriptContent);
        const params = eventComment ? CommentUtils.extractParams(eventComment) : [];
        
        const args: ComponentEventArgument[] = params.map(param => ({
          name: param.name,
          type: param.type || 'any',
          description: param.description,
        }));
        
        events.push({
          name: eventName,
          description: eventComment ? CommentUtils.extractDescription(eventComment) : '',
          arguments: args,
        });
      }
    }
    
    // 从脚本中查找直接的$emit调用
    const scriptEmitMatches = [...scriptContent.matchAll(/\$emit\s*\(\s*['"]([^'"]+)['"]/g)];
    
    for (const match of scriptEmitMatches) {
      const eventName = match[1];
      
      // 检查事件是否已存在
      const existingEvent = events.find(e => e.name === eventName);
      if (!existingEvent) {
        // 查找脚本中对该事件的定义，以获取参数信息
        const eventComment = this.findEventComment(eventName, scriptContent);
        const params = eventComment ? CommentUtils.extractParams(eventComment) : [];
        
        const args: ComponentEventArgument[] = params.map(param => ({
          name: param.name,
          type: param.type || 'any',
          description: param.description,
        }));
        
        events.push({
          name: eventName,
          description: eventComment ? CommentUtils.extractDescription(eventComment) : '',
          arguments: args,
        });
      }
    }
    
    return events;
  }
  
  /**
   * 提取组件插槽
   * @param parsedComponent 解析后的组件对象
   * @param filePath 文件路径
   * @returns 组件插槽数组
   */
  private async extractSlots(parsedComponent: any, filePath: string): Promise<ComponentSlot[]> {
    const slots: ComponentSlot[] = [];
    
    if (!parsedComponent.template?.content) {
      return slots;
    }
    
    const templateContent = parsedComponent.template.content;
    
    // 查找命名插槽
    const namedSlotMatches = [...templateContent.matchAll(/<slot\s+name=(['"])([^'"]+)\1[^>]*>/g)];
    
    for (const match of namedSlotMatches) {
      const slotName = match[2];
      const slotTag = match[0];
      
      // 检查插槽是否已存在
      const existingSlot = slots.find(s => s.name === slotName);
      if (!existingSlot) {
        // 查找slot上的属性，它们可能是绑定变量
        const bindingMatches = [...slotTag.matchAll(/\s+:([^=]+)=(['"])([^'"]+)\2/g)];
        const bindings: ComponentSlotBinding[] = [];
        
        for (const bindingMatch of bindingMatches) {
          bindings.push({
            name: bindingMatch[1],
            type: 'any', // 默认类型
            description: '',
          });
        }
        
        const slotComment = this.findSlotComment(slotName, templateContent);
        slots.push({
          name: slotName,
          description: slotComment ? CommentUtils.extractDescription(slotComment) : '',
          bindings: bindings,
        });
      }
    }
    
    // 查找默认插槽
    const defaultSlotMatch = templateContent.match(/<slot\s+[^>]*>/);
    if (defaultSlotMatch) {
      const slotTag = defaultSlotMatch[0];
      
      // 检查默认插槽是否已存在
      const existingDefaultSlot = slots.find(s => s.name === 'default');
      if (!existingDefaultSlot) {
        // 查找slot上的属性，它们可能是绑定变量
        const bindingMatches = [...slotTag.matchAll(/\s+:([^=]+)=(['"])([^'"]+)\2/g)];
        const bindings: ComponentSlotBinding[] = [];
        
        for (const bindingMatch of bindingMatches) {
          bindings.push({
            name: bindingMatch[1],
            type: 'any',
            description: '',
          });
        }
        
        const slotComment = this.findSlotComment('default', templateContent);
        slots.push({
          name: 'default',
          description: slotComment ? CommentUtils.extractDescription(slotComment) : '',
          bindings: bindings,
        });
      }
    }
    
    return slots;
  }
  
  /**
   * 提取组件方法
   * @param parsedComponent 解析后的组件对象
   * @param filePath 文件路径
   * @returns 组件方法数组
   */
  private async extractMethods(parsedComponent: any, filePath: string): Promise<ComponentMethod[]> {
    const methods: ComponentMethod[] = [];
    
    if (!parsedComponent.script?.content) {
      return methods;
    }
    
    const scriptContent = parsedComponent.script.content;
    
    // 查找methods对象
    const methodsMatch = scriptContent.match(/methods\s*:\s*\{([\s\S]*?)\}(?:,|\s*$)/);
    if (!methodsMatch) {
      return methods;
    }
    
    const methodsBlock = methodsMatch[1];
    
    // 提取方法定义
    const methodMatches = [...methodsBlock.matchAll(/(\w+)\s*(?:\([^)]*\))?\s*\{/g)];
    
    for (const match of methodMatches) {
      const methodName = match[1];
      
      // 跳过内部或私有方法（以下划线开头）
      if (methodName.startsWith('_')) {
        continue;
      }
      
      // 查找方法注释
      const methodComment = this.findMethodComment(methodName, scriptContent);
      
      // 提取参数
      const params: ComponentMethodParam[] = [];
      const methodDef = new RegExp(`${methodName}\\s*\\(([^)]*)\\)\\s*\\{`, 'g').exec(methodsBlock);
      
      if (methodDef) {
        const paramsString = methodDef[1] || '';
        
        // 解析参数列表
        const paramNames = paramsString.split(',').map(p => p.trim()).filter(Boolean);
        
        // 从注释中提取参数信息
        const commentParams = methodComment ? CommentUtils.extractParams(methodComment) : [];
        
        for (const paramName of paramNames) {
          // 从注释中查找参数描述
          const commentParam = commentParams.find(p => p.name === paramName);
          
          params.push({
            name: paramName,
            type: commentParam?.type || 'any',
            description: commentParam?.description || '',
          });
        }
      }
      
      // 提取返回类型和描述
      const returnType = CommentUtils.extractReturnType(methodComment) || 'any';
      const returnDescription = CommentUtils.extractReturnDescription(methodComment) || '';
      
      methods.push({
        name: methodName,
        description: methodComment ? CommentUtils.extractDescription(methodComment) : '',
        params: params,
        returns: {
          type: returnType,
          description: returnDescription,
        },
      });
    }
    
    return methods;
  }
  
  /**
   * 映射Vue类型声明到字符串类型
   * @param vueType Vue类型（String, Number等）
   * @returns 映射后的类型字符串
   */
  private mapVueTypeToString(vueType: string): string {
    switch (vueType.trim()) {
      case 'String': return 'string';
      case 'Number': return 'number';
      case 'Boolean': return 'boolean';
      case 'Array': return 'array';
      case 'Object': return 'object';
      case 'Function': return 'function';
      case 'Date': return 'date';
      case 'Symbol': return 'symbol';
      default: return vueType.toLowerCase();
    }
  }
  
  /**
   * 查找属性注释
   * @param propName 属性名
   * @param scriptContent 脚本内容
   * @returns 属性注释
   */
  private findPropComment(propName: string, scriptContent: string): string | null {
    // 查找属性的注释
    const propCommentPattern = new RegExp(`\\/\\*\\*((?:[^*]|\\*[^/])*)\\*\\/\\s*(?:${propName}\\s*:|${propName}\\s*,)`, 's');
    const commentMatch = propCommentPattern.exec(scriptContent);
    
    if (commentMatch) {
      return commentMatch[1];
    }
    
    return null;
  }
  
  /**
   * 查找属性描述
   * @param propName 属性名
   * @param scriptContent 脚本内容
   * @returns 属性描述
   */
  private findPropDescription(propName: string, scriptContent: string): string {
    const propComment = this.findPropComment(propName, scriptContent);
    return propComment ? CommentUtils.extractDescription(propComment) : '';
  }
  
  /**
   * 查找事件注释
   * @param eventName 事件名
   * @param scriptContent 脚本内容
   * @returns 事件注释
   */
  private findEventComment(eventName: string, scriptContent: string): string | null {
    // 查找事件的注释，通常在$emit调用前
    const eventCommentPattern = new RegExp(`\\/\\*\\*((?:[^*]|\\*[^/])*)\\*\\/[\\s\\S]*?\\$emit\\s*\\(\\s*['"]${eventName}['"]`, 's');
    const commentMatch = eventCommentPattern.exec(scriptContent);
    
    if (commentMatch) {
      return commentMatch[1];
    }
    
    return null;
  }
  
  /**
   * 查找插槽注释
   * @param slotName 插槽名
   * @param templateContent 模板内容
   * @returns 插槽注释
   */
  private findSlotComment(slotName: string, templateContent: string): string | null {
    // 查找slot标签前的注释
    const slotPattern = slotName === 'default' 
      ? /(<!--((?:[^-]|(?:-(?!->)))*)--->)?\s*<slot\s+[^>]*>/
      : new RegExp(`(<!--((?:[^-]|(?:-(?!->)))*)--->)?\\s*<slot\\s+name=['"']${slotName}['"'][^>]*>`, 's');
    
    const slotMatch = slotPattern.exec(templateContent);
    
    if (slotMatch && slotMatch[1]) {
      // 提取注释内容
      const comment = slotMatch[2];
      if (comment) {
        return comment;
      }
    }
    
    return null;
  }
  
  /**
   * 查找方法注释
   * @param methodName 方法名
   * @param scriptContent 脚本内容
   * @returns 方法注释
   */
  private findMethodComment(methodName: string, scriptContent: string): string | null {
    // 查找方法的注释，通常在methods对象内的方法定义前
    const methodCommentPattern = new RegExp(`\\/\\*\\*((?:[^*]|\\*[^/])*)\\*\\/\\s*${methodName}\\s*[(:]`, 's');
    const commentMatch = methodCommentPattern.exec(scriptContent);
    
    if (commentMatch) {
      return commentMatch[1];
    }
    
    return null;
  }
  
  /**
   * 提取注释
   * @param content 源代码内容
   * @returns 注释数组
   */
  private extractComments(content: string): string[] {
    const comments: string[] = [];
    
    // 提取块注释 /* ... */
    const blockCommentPattern = /\/\*\*((?:[^*]|\*[^/])*)\*\//g;
    const blockMatches = [...content.matchAll(blockCommentPattern)];
    
    for (const match of blockMatches) {
      comments.push(match[1]);
    }
    
    // 提取行注释 //
    const lineCommentPattern = /\/\/\s*(.*)/g;
    const lineMatches = [...content.matchAll(lineCommentPattern)];
    
    for (const match of lineMatches) {
      comments.push(match[1]);
    }
    
    return comments;
  }
} 